package su.levenetc.ohos.draggableview;

import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.VelocityDetector;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.ThreeDimView;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.Point;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.TouchEvent;
import su.levenetc.ohos.draggableview.utils.Utils;
import su.levenetc.ohos.draggableview.utils.VelocityVector;

/**
 * Created by Eugene Levenetc.
 */
public abstract class DraggableView extends Component implements Component.DrawTask {
    protected static final float MAX_VEL = 30f;

    protected final Paint paint = new Paint();
    protected ThreeDimView camera = new ThreeDimView();
    protected final Matrix cameraMatrix = new Matrix();
    protected final VelocityVector velocityVector;

    protected PixelMap bitmap;
    protected Point downEventPoint;
    private DragController.IDragViewGroup dragViewGroup;
    protected TouchEvent motionEvent;
    protected final float xCanvasTranslation;
    protected final float yCanvasTranslation;

    protected DraggableView(
            Context context,
            PixelMap bitmap,
            VelocityDetector velocityTracker,
            Point selectedViewPoint,
            Point downEventPoint,
            DragController.IDragViewGroup dragViewGroup) {
        super(context);
        this.bitmap = bitmap;
        this.downEventPoint = downEventPoint;
        this.dragViewGroup = dragViewGroup;

        velocityVector = new VelocityVector(
                velocityTracker, getResourceManager().getDeviceCapability().screenDensity
        );

        //it is used to enlarge canvas zone
        //otherwise camera's frustum cuts bitmap
        float scale = 0.9f;
        xCanvasTranslation = (int) (bitmap.getImageInfo().size.width * scale);
        yCanvasTranslation = (int) (bitmap.getImageInfo().size.height * scale);

        int width = (int) (bitmap.getImageInfo().size.width + xCanvasTranslation * 2);
        int height = (int) (bitmap.getImageInfo().size.height + yCanvasTranslation * 2);

        setContentPositionX(selectedViewPoint.getPointX() - xCanvasTranslation);
        setContentPositionY(selectedViewPoint.getPointY() - yCanvasTranslation);

        setLayoutConfig(new ComponentContainer.LayoutConfig(width, height));

        paint.setAntiAlias(true);
        paint.setFilterBitmap(true);

        velocityVector.setMaxVel(MAX_VEL);

        addDrawTask(this);
    }

    protected abstract boolean render(Canvas canvas);

    @Override
    public void onDraw(Component component, Canvas canvas) {
        boolean isUpdated = render(canvas);
        if (isUpdated) {
            getContext().getUITaskDispatcher().asyncDispatch(() -> invalidate());
        }
    }

    public void onMoveAction(TouchEvent event, Component component) {
        this.motionEvent = event;
        setContentPositionX(Utils.getTouchX(event, component, 0) - downEventPoint.getPointX() - xCanvasTranslation);
        setContentPositionY(Utils.getTouchY(event, component, 0) - downEventPoint.getPointY() - yCanvasTranslation);
        invalidate();
        dragViewGroup.onMoveEvent(
                Utils.getTouchX(event, component) - downEventPoint.getPointX(),
                Utils.getTouchY(event, component) - downEventPoint.getPointY()
        );
    }

    public float getXTranslation() {
        return xCanvasTranslation;
    }

    public float getYTranslation() {
        return yCanvasTranslation;
    }

}
